Quick Start PRO
AVCaptureSession is the low-level building block for camera and microphone capture in Scripting. It is the same API that VideoRecorder is built on top of — but exposed as discrete, composable objects so that you can assemble your own pipeline: choose a device, attach inputs and outputs, run the session, and respond to the iPhone 16 hardware Camera Control.
If you just want to "press a button and record an mp4", reach for VideoRecorder — it manages the state machine, audio session, orientation and pause/resume timeline for you. Use AVCaptureSession when you need:
- QR / barcode scanning while previewing video
- Custom photo capture (HEVC, flash mode, Live Photo)
- A custom recording flow that does not match
VideoRecorder's state machine - iPhone 16 Camera Control bindings (zoom slider, exposure slider, custom controls)
- Multiple outputs simultaneously (e.g. photo + movie)
PRO is required to call startRunning(), capturePhoto() and startRecording(). Construction, configuration and canAdd* checks are free.
Pipeline at a glance
Permissions
You don't request camera or microphone permission yourself. session.startRunning() inspects the inputs you have attached, prompts the user the first time, and rejects the promise if they deny. Other Scripting APIs (Photos, Contacts, Location) work the same way — the API call is the permission gate.
Picking a device
AVCaptureDevice.default(mediaType) is the simplest path. For a specific lens or position use AVCaptureDevice.defaultDevice(...) or AVCaptureDevice.discoverySession(...):
Adding inputs and outputs
Wrap the device in an AVCaptureDeviceInput (the constructor throws if the device is busy or denied), then attach outputs. Use session.configure(...) to batch your changes — it wraps beginConfiguration() / commitConfiguration() for you.
Calling
addInput/addOutputoutside ofconfigure(...)works too, but each mutation hits the queue separately. Group them when you can.
Photo capture
The resolved object has image: UIImage, metadata: Record<string, any>, and isRawPhoto: boolean.
Movie recording
startRecording resolves when the file is fully finalized; do not delete the file before the promise resolves.
QR / barcode scanning
AVCaptureMetadataOutput runs the system code detector on the live frames.
Set rectOfInterest = { x, y, width, height } (normalized 0..1) to limit detection to a region of the frame.
Each detected object carries a raw bounds (normalized 0..1) and, for codes, raw corners. It also carries a transformed field whose bounds / corners are corrected for the connection's orientation and mirroring — use those when drawing an overlay on top of the preview:
To convert a rectangle between an output's own coordinate space and the metadata output's normalized space, use output.metadataOutputRectConverted({ x, y, width, height }) and its inverse output.outputRectConverted(...). Both are available on every output and return { x, y, width, height }.
Showing a preview
Use <CaptureVideoPreviewView session={session} videoDevice={camera}/> in any UI you build with Scripting's view layer. See the Preview View page for the full prop list.
Cleanup
When you are done with the session — typically in onAppear/onDisappear of your component, or before navigating away — stop and dispose:
dispose() is idempotent. If you forget it, the wrapper is also released when the running script ends.
